package org.springframework.aop.framework;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectInstanceFactory;
import org.springframework.aop.aspectj.AspectJAfterReturningAdvice;
import org.springframework.aop.aspectj.AspectJAroundAdvice;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.AspectJMethodBeforeAdvice;
import org.springframework.aop.aspectj.SingletonAspectInstanceFactory;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.framework.ReflectiveMethodInvocation;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
import org.springframework.aop.support.DefaultPointcutAdvisor;

import com.demo.spring.aop底层演示.demo2.Aspect;
import com.demo.spring.aop底层演示.demo2.Target;

//其它见《com.demo.spring.aop底层演示.demo2》
//Test类在org.springframework.aop.framework里，为了可以调用受保护的方法
public class Test {
	
	public static void main(String[] args) throws Throwable {
		AspectInstanceFactory factory = new SingletonAspectInstanceFactory(new Aspect());
		// 高级切面转换为低级切面
		List<Advisor> list = new ArrayList<Advisor>();
		for(Method method : Aspect.class.getDeclaredMethods()) {
			if(method.isAnnotationPresent(Before.class)) {
				// 解析切点
				String expression = method.getAnnotation(Before.class).value();
				AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
				pointcut.setExpression(expression);
				// 通知类
				AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(method, pointcut, factory);
				// 切面
				Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
				list.add(advisor);
			} else if(method.isAnnotationPresent(AfterReturning.class)) {
				// 解析切点
				String expression = method.getAnnotation(AfterReturning.class).value();
				AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
				pointcut.setExpression(expression);
				// 通知类
				AspectJAfterReturningAdvice advice = new AspectJAfterReturningAdvice(method, pointcut, factory);
				// 切面
				Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
				list.add(advisor);
			} else if(method.isAnnotationPresent(Around.class)) {
				// 解析切点
				String expression = method.getAnnotation(Around.class).value();
				AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
				pointcut.setExpression(expression);
				// 通知类
				AspectJAroundAdvice advice = new AspectJAroundAdvice(method, pointcut, factory);
				// 切面
				Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
				list.add(advisor);
			}
		}
		
		for (Advisor advisor : list) {
			System.out.println(advisor);
		}
		
		// 解析完之后，最终需要转换为环绕通知MethodInterceptor：AspectJAroundAdvice已经实现了MethodInterceptor，所以无需转换，另外两个需要转换
		Target target = new Target();
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.setTarget(target);
		proxyFactory.addAdvice(ExposeInvocationInterceptor.INSTANCE);
		proxyFactory.addAdvisors(list);
		List<Object> methodInterceptorList = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod("foo"), Target.class);
		for (Object o : methodInterceptorList) {
			System.out.println(o);
		}
		
		// 创建并执行调用链
		MethodInvocation methodInvocation = new ReflectiveMethodInvocation(null, target, Target.class.getMethod("foo"), new Object[0], Target.class, methodInterceptorList);
		methodInvocation.proceed();
	}

}
